
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Redis类型的底层实现 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>Redis类型的底层实现 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">结构</div>
          <div class="card-question">Redis内部使用什么通用结构体来表示所有数据类型？它的主要字段及其作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">结构</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Redis使用 RedisObject（或 robj）作为通用结构体。其主要字段包括：<br>- type: 4位整数，标识数据类型（如字符串、列表等）。<br>- encoding: 4位整数，标识数据的底层编码方式（如int, embstr, ziplist等）。<br>- lru: 用于LRU缓存淘汰策略，记录对象的最近使用情况。<br>- refcount: 引用计数，用于管理内存的释放和回收。<br>- ptr: 一个指针，指向存储实际数据的内存地址。</div>
          </div>
          <div class="card-source">来源: RedisObject结构 - 1. RedisObject的结构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">Redis的简单动态字符串（SDS）相比传统的C语言字符串（char*）有哪些核心优势？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">SDS的核心优势包括：<br>1. **安全性**：通过记录字符串长度（len），SDS可以有效避免缓冲区溢出的问题。<br>2. **效率**：获取字符串长度的操作时间复杂度为O(1)，因为长度信息被缓存。<br>3. **可变性**：SDS可以根据需要自动扩展或收缩，无需手动管理内存。<br>4. **二进制安全**：SDS可以存储任意二进制数据，包括空字符（'\0'）。</div>
          </div>
          <div class="card-source">来源: String类型的底层实现 - 8. SDS与C字符串的区别 & 1. 简单动态字符串（SDS）</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Redis的Hash类型在什么条件下会从`ziplist`（压缩列表）编码转换为`hashtable`（哈希表）编码？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当满足以下任一条件时，Redis会将Hash类型的数据结构从`ziplist`转换为`hashtable`：<br>1. 哈希对象中的键值对数量超过了 `hash-max-ziplist-entries` 配置项的值（默认为512）。<br>2. 任意一个键或值的长度超过了 `hash-max-ziplist-value` 配置项的值（默认为64字节）。</div>
          </div>
          <div class="card-source">来源: Hash 类型的底层实现 - 3. 数据结构选择</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Redis的List类型在底层实现上是如何根据数据规模选择不同数据结构的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Redis的List类型会根据元素的数量和大小来选择底层数据结构。当列表元素较少且每个元素的长度较短时（由`list-max-ziplist-entries`和`list-max-ziplist-value`参数控制），Redis会使用`ziplist`（压缩列表）以节省内存。当列表元素数量或任一元素长度超过阈值时，会自动转换为`linkedlist`（双向链表）以保证高效的插入和删除性能。</div>
          </div>
          <div class="card-source">来源: List 类型的底层实现 - 3. 数据结构选择</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Redis的Set类型在什么情况下会使用`intset`（整数集合），而在什么情况下会使用`hashtable`（哈希表）？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Redis Set类型的底层实现选择依据是：<br>1. 当集合中的所有元素都是整数，并且元素数量较少时（通常小于512个），会使用`intset`（整数集合）来节省内存。<br>2. 当集合中包含非整数类型的元素，或者元素数量较多时，会使用`hashtable`（哈希表）。</div>
          </div>
          <div class="card-source">来源: Set 类型的底层实现 - 3. 数据结构选择</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">Redis的Sorted Set（有序集合）为什么选择使用跳表（skiplist）而不是红黑树作为其核心底层实现之一？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">尽管跳表和红黑树在查找、插入和删除操作上的平均时间复杂度都是O(log N)，但Redis选择跳表的主要原因有：<br>1. **实现复杂度**：跳表的实现相对简单，易于调试和维护；而红黑树的旋转和重平衡操作相对复杂。<br>2. **性能稳定性**：跳表通过随机化来保持高效的性能，在多数情况下表现良好。</div>
          </div>
          <div class="card-source">来源: Sorted Set 类型的底层实现 - 7. 跳表与红黑树的比较</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">实现</div>
          <div class="card-question">Redis的Bitmap类型是如何实现的？它依赖于哪种基础数据结构？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">实现</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Bitmap的底层实现依赖于Redis的String数据结构。它是一个以位为单位的数组，每个二进制位映射到字符串的某一位，字符串的每个字节（8位）可以存储8个Bitmap位。Redis通过提供`SETBIT`、`GETBIT`、`BITCOUNT`等位操作命令来管理和操作Bitmap数据。</div>
          </div>
          <div class="card-source">来源: Bitmap类型的底层实现 - 2. Bitmap存储结构</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">优化</div>
          <div class="card-question">当Redis的哈希表需要扩展容量（rehash）时，为了避免性能抖动，它采用了什么策略？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">优化</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">为了避免rehash操作带来的性能抖动，Redis采用了“渐进式rehash”策略。rehash过程不是一次性完成的，而是分步进行的。在此期间，Redis会同时维护旧哈希表和新哈希表，每次对哈希表进行增删改查操作时，会顺带将一部分旧哈希表的键值对迁移到新哈希表，直到迁移全部完成。</div>
          </div>
          <div class="card-source">来源: Hash 类型的底层实现 - 4. 性能优化</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">算法</div>
          <div class="card-question">Redis的HyperLogLog（HLL）主要用于解决什么问题？它的核心思想是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">算法</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">HyperLogLog（HLL）是一种概率型数据结构，主要用于在消耗极少且固定的内存空间下，对大规模数据集的唯一元素数量（即基数）进行估算。<br>其核心思想是：利用元素哈希值中的前导零（Leading Zero）规律来估计基数。通过一组稀疏的计数器（registers）记录观察到的最大前导零位数，并结合概率算法，从而估算出集合中不重复元素的个数。</div>
          </div>
          <div class="card-source">来源: HyperLogLog类型底层实现 - 1. 基本概念 & 2. HyperLogLog的存储结构</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
